import java.applet.Applet;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Point;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;

import javax.imageio.ImageIO;

//stages
//maps with ground interaction
//scrolling bgs upon wave completion 
//random off-screen enemy spawning within a wave
//character crouching
//enemy foot movement

//then.....

//title screen
//character selection?
//timed waves?
//score counter
//different guns or power-ups
//ammo?

//then

//AJ mode


@SuppressWarnings("serial")
public class SlugGame extends Applet implements MouseMotionListener, MouseListener, Runnable, KeyListener {
	private BufferedImage background;
    private Image backbuffer;
    private BufferedImage startScreen;
    private int death;
    private int trueX;
    private int width;
    private int height;
    private int time;
    private int onScreenEnems;
    private int stagesPassed;
    private Graphics bg;
    private Character player;
    private ArrayList<Bullet> bullets=new ArrayList<Bullet>();
    private Thread runner;
    private int frame;
    private Point mousePoint;
    private int stageCount;
    private int enemyQ;
    private int enemiesKilled;
    private int totalKilled;
    private int frameCounter;
    private ArrayList<Enemy> enemies;
    private BufferedImage head;
    private BufferedImage sky;
    private BufferedImage arrow;
    private boolean isBetween;
    private int movementTime;
    private int downTime;
    private boolean movingRight;
    private boolean movingLeft;
    private Stage currentStage;
    private int state; // state 0 is start screen, 1 is main game, 2 is end?
    private boolean stagePassed;
    private boolean nextStage;
    private Stage[] stages;
    
    public void init(){
    	
    	//initializes 
    	stagePassed = false;
    	nextStage = false;
    	state = 0;
    	stagesPassed = 0;
    	downTime = 0;
    	time = 0;
    	onScreenEnems = 3;
    	width = 600;
    	height = 352;
        setSize(width, height);
        trueX = 0;
        try{
        	background = ImageIO.read(new File("backgroundReal.png"));
        	head = ImageIO.read(new File("rossi head.png"));
        	sky = ImageIO.read(new File("skyBackground.png"));
        	startScreen = ImageIO.read(new File("start Screen.png"));
        	arrow = ImageIO.read(new File("redArrow.png"));
        	
		} catch (IOException e) {
			e.printStackTrace();
		}
        player = new Character(new Point(50, 270));
        enemies = new ArrayList<Enemy>();
        stageCount = 1;
        enemyQ = 3;
        enemiesKilled = 0;
        totalKilled = 0;
        enemies.add(new Enemy(new Point(200, 123)));
        enemies.add(new Enemy(new Point(250, 187)));
        enemies.add(new Enemy(new Point(300, 251)));
        
        //constructing new stages
        stages = new Stage[5];
        
        currentStage = new Stage();
        
        currentStage.setGroundLevels(0, 600, 270);
        currentStage.setPlatformOneLevels(0, 600, 187);
        currentStage.setPlatformTwoLevels(0, 600, 123);
        currentStage.setPlatformTwoLevels(215, 280, 82);
        currentStage.setPlatformTwoLevels(505, 570, 82);
        
        Stage stage2 = new Stage();
        
        stage2.setGroundLevels(0, 600, 270);
        stage2.setPlatformOneLevels(0, 517, 187);
        stage2.setPlatformOneLevels(527, 600, 273);
        stage2.setPlatformTwoLevels(0, 450, 123);
        
        Stage stage3 = new Stage();
        
        stage3.setGroundLevels(0, 247, 270);
        stage3.setGroundLevels(230, 600, 167);
        stage3.setPlatformOneLevels(360, 600, 105);
        
        
        
        stage3.setGroundLevels(252, 600, 167);
        stage3.setPlatformOneLevels(252, 600, 167);      
        stage3.setPlatformOneLevels(0, 252, 270);
        stage3.setPlatformTwoLevels(230, 363, 167);
        stage3.setPlatformTwoLevels(363, 600, 105);
        

        Stage stage4 = new Stage();
        
        stage4.setGroundLevels(0, 570, 167);
        stage4.setGroundLevels(570, 600, 247);
        stage4.setPlatformOneLevels(0, 12, 167);
        stage4.setPlatformOneLevels(0, 477, 105);
        stage4.setPlatformOneLevels(355, 476, 105);
        stage4.setPlatformOneLevels(476, 600, 167);
        
        //currentStage=stage3;
        stages[0] = currentStage;
        stages[1] = stage2;
        stages[2] = stage3;
        stages[3] = stage4;
        
        backbuffer=createImage(getSize().width, getSize().height);
        bg=backbuffer.getGraphics();
        bg.setFont(new Font("Cooper Black", Font.PLAIN, 18));
        runner = new Thread(this);
        runner.start();
        mousePoint = new Point(0, 0);
        addKeyListener(this);
        addMouseMotionListener(this);
        addMouseListener(this);
    }
   
    public void paintAll(Graphics g){
    	if(state == 0){
    		g.drawImage(startScreen, 0, 0, null);
    	}
    	else if(state == 1){
    		g.clearRect(0, 0, getSize().width, getSize().height);
        	g.drawImage(sky, 0, 0, null);
            g.drawImage(background, -trueX,0,null);
            Color Green = new Color(10, 250, 10, 250);
            Color lightGreen = new Color(10, 250, 10, 150);
            //g.drawString("Frame: " + frame, 10, 200);
            g.drawString("Points: " + totalKilled * 25, 10, 20);
            if(stagePassed && !(frame%100 < 50)){
            	g.drawImage( arrow, 400, 100, null);
            }            
            g.drawString("Lives: ", 300, 40);
            int headX = 360;
            for(int i = 0; i < player.getLives(); i++){
            	g.drawImage(head, headX, 15, null);
            	headX += 45;
            }
            g.drawString("Health:", 5, 60);
            g.fillRect(73, 33, 2 * player.getMaxHealth() + 4, 44);
            g.setColor(Color.white);
            g.fillRect(75, 35, 2 * player.getMaxHealth(), 40);
            g.setColor(lightGreen);
            paintRect(g);
            g.setColor(Green);
            g.fillRect(75, 35, 2 * player.getHealth(), 40);
            g.setColor(Color.black);
            if((!player.isDead() && !isBetween) || (isBetween && frame%40<20)){
            	g.drawImage(player.getBody(), player.getX(), player.getY(), null);
               	g.drawImage(player.getLegs(frame), player.getLegPoint().x, player.getLegPoint().y, null);
            	g.drawImage(player.getArm(mousePoint), player.getArmPoint().x, player.getArmPoint().y, null);
            }
            else if(player.isDead()){
            	g.drawImage(player.getDeath(death), player.getX(), player.getY() - 20, null);
            }         
            for(Enemy enemy : enemies){
            	g.drawImage(enemy.getImage(), enemy.getX(), enemy.getY(), null);
            }
            for(int j = 0; j < bullets.size(); j++){
                g.drawImage(bullets.get(j).getImage(), bullets.get(j).getX(), bullets.get(j).getY(), null);
            }
            g.drawString(mousePoint.toString(), 10, 110);
            g.drawString(player.getPoint().toString(), 10, 130);
	    }
    }
   
   private void paintRect(Graphics g){
	   if(player.isDamaged()){
		   g.fillRect(75, 35, (2 * player.getHealth()) + time, 40);
		   if(frame % 2 == 0){
			   time--;
		   }
	   }
	   if(time == 0){
		   player.setDamaged(false);
	   }
   }
   
   public void update(Graphics g){
	   paintAll(bg);
       g.drawImage(backbuffer, 0, 0, this);
   }
   
   public void paint(Graphics g){
       update(g);
   }
   
   public void run(){
	   while(true){
		   if(player.getY() <= 10){
			   player.setY(currentStage.getGround(player.getPoint()));
		   }
		   if(state == 1){
			   	if(isBetween){
			   		downTime++;
			   	}
			   	if(downTime >= 150){
			   		downTime = 0;
			   		isBetween = false;
			   	}
			   	if(player.isDead()){
			   		frameCounter++;
				   	if(death == 0){
				   		death++;
				   	}
				   	if(death >= 1 && frameCounter % 15 == 0){
				   		death++;
				   	}
				   	if(death == 5){
				   		player.recover();
				   		death = 0;
				   	}
			   	}
			   	if(player.getX() >= 230 && stageCount == 3 && player.getY() > 207){
			   		player.setD(false);
			   	}
			   	if(movingLeft && stagePassed){
			   		player.setA(false);
			   		player.setLeft(true);
			   		movementTime++;
			   		trueX -= 2;
			   		if(movementTime >= 300){
				   		player.setLeft(false);
				   		movementTime = 0;
				   		movingLeft = false;
				   		stagePassed = false;
				   		nextStage = true;
				   		System.out.println(nextStage);
				   		player.setIsMoving(false);
			   		}
			   	}			   	
			   	if(movingRight && stagePassed){
			   		player.setD(false);
			   		player.setRight(true);
			   		movementTime++;			   		
			   		trueX += 2;
			   		if(movementTime >= 300){
				   		player.setRight(false);
				   		movementTime = 0;
				   		nextStage = true;
				   		stagePassed = false;
				   		movingRight = false;
				   		player.setIsMoving(false);
			   		}
			   	}			   	
	       		player.shoot(bullets, mousePoint, frame);
	        	if(player.getArmPoint().x >= (600 - 50) && trueX <= 1600 && player.isMoving() && stagePassed){
	        		movingRight = true;
	        		player.setIsMoving(true);
	        	}
	        	
	        	/*else if(player.getArmPoint().x<=50 && trueX>0 && player.isMoving() && stagePassed){
	        		movingLeft=true;
	        		player.setIsMoving(true);
	        	}*/
	        	if(frame % 3 == 0){
	        		for(Enemy enemy : enemies){
	                   enemy.move(player.getPoint());
	                    if((frame + 30) % (Math.round(Math.random() * 50) + 40) == 0 && !player.isDead()){
	                    	enemy.shoot(bullets, player.getPoint());
	                    }
	            	}
	            }
	        	boolean remove = false;
			for(int i = 0; i < bullets.size(); i++){
	            bullets.get(i).move();
	            if(bullets.get(i).middle().x < 0 || bullets.get(i).middle().x > width ||
	            	bullets.get(i).middle().y < 0 || bullets.get(i).middle().y > height && !isBetween){
	            	remove = true;
	            }
	            if(bullets.get(i).isEnemys() && player.isCollided(bullets.get(i).middle()) && !player.isDead() && !isBetween){
	            	player.loseHealth();
	            	time += 20;
	            	remove = true;
	            	if(player.getHealth() == 0 && !player.isDead()){
	            		death = 0;
	            		player.loseLife();
	            		isBetween = true;
	            	}
	            	if(player.getLives() == 0){
	            		//System.out.println("Game Over!");
	            	}
	            }
	            else{
	            	for(int j = 0; j < enemies.size(); j++){
	                	if(!bullets.get(i).isEnemys() && enemies.get(j).isCollided(bullets.get(i).middle())){
	                		enemies.get(j).loseHealth();
	                		remove = true;
	                	}
	                }
	            }
	            if(remove){
	                bullets.remove(bullets.get(i));
	            }
	            remove = false;
	        }
	        for(int i = enemies.size() - 1;i >= 0; i--){
	        	if (enemies.get(i).getHealth() <= 0){
	        		enemies.remove(i);
	        		enemiesKilled++;
	        		totalKilled++;
	        		
	        		//System.out.println("Enemies Killed:" + enemiesKilled);
	        	}
	        }
	        
	        if(enemiesKilled+enemies.size() < enemyQ && enemies.size() <= onScreenEnems){
	        	int love = (int)(Math.random() * 3);
	        	int randHeight = (int) (Math.random() * height);
	        	if(love == 0){
	        		enemies.add(new Enemy(new Point(610, currentStage.getGround(new Point(600, randHeight)))));
	        	}else if (love == 1){
	        		enemies.add(new Enemy(new Point(-30, currentStage.getGround(new Point(0, randHeight)))));
	        	}
	        	else{
	        		enemies.add(new Enemy(new Point(randHeight + 50, -20)));
	        	}
	        }
	       
	        if(enemiesKilled == enemyQ){
	        	stagePassed = true;
	        	if(nextStage){
	        		stageCount++;
	        		stagesPassed++;
	        		System.out.println(stageCount);
	        		enemiesKilled = 0;
	        		if(stagesPassed == 1 || stagesPassed== 2){
	        			enemyQ = 5;
	        		}else if (stagesPassed == 3){
	        			enemyQ = 8;
	        			onScreenEnems = 4;
	        		}else if (stagesPassed == 4){
	        			enemyQ = 10;
	        			onScreenEnems = 5;
	        		}else if (stagesPassed == 5){
	        			enemyQ = 13;
	        			onScreenEnems = 6;
	        		}
	        		nextStage = false;
	        		currentStage.reset();
	        		currentStage = stages[stageCount - 1];
	            	enemies.add(new Enemy(new Point(610, currentStage.getGround(new Point(300, 0)))));	      
	            	stagePassed = false;
	        	}
	        }
	        for(Enemy e: enemies){
	        	if(e.getX() > 0 && e.getX() < 600 && e.getY() < currentStage.getGround(e.getPoint())){
	        		e.getPoint().y++;
	        	}
	        }
	        frame++;
	        player.move(width, frame, currentStage);
	        repaint();
	        try {
	        	Thread.sleep(6); // pause between frames
	        } catch (InterruptedException e) {
	        	e.printStackTrace();
	        }
	    }
	   }
   }
   
    @Override 
    public void mouseClicked(MouseEvent e) {
    	if(!player.isDead()){
    		player.setMouseClicked(true); 
    	}
    }
    
    @Override
    public void mouseMoved(MouseEvent e) {
    	mousePoint = e.getPoint();
    }

    @Override
    public void mouseEntered(MouseEvent arg0) {
    	setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
    }

    @Override
    public void mouseExited(MouseEvent arg0) {
            // TODO Auto-generated method stub
    }

    @Override
    public void mousePressed(MouseEvent arg0) {
    	player.setMouseDown(true);
    }  

    @Override
    public void mouseReleased(MouseEvent arg0) {
    	player.setMouseDown(false);       
    }

    @Override
    public void mouseDragged(MouseEvent arg0) {
    	mousePoint = arg0.getPoint();           
    }

    @Override
    public void keyPressed(KeyEvent arg0) {
    	if(state == 0){
    		if(arg0.getKeyCode() == KeyEvent.VK_ENTER){
    			state = 1;
    		}
    	}
    	if(state == 1){
	    	if(!player.isDead()){
		        if(arg0.getKeyCode() == KeyEvent.VK_A){
		        	if(!movingLeft && !movingRight){
		        		player.setA(true);
		        	}
		        	player.setIsMoving(true);
		        }
		        if(arg0.getKeyCode() == KeyEvent.VK_D){
		        	if(!movingRight && !movingLeft && !(player.getX() >= 230 && stageCount == 3 && player.getY() > 220)){
		        		player.setD(true); 
		        	}
		        	player.setIsMoving(true);
		        }
		        if(arg0.getKeyCode() == KeyEvent.VK_S){
		        	if(!movingLeft && !movingRight){
		        	player.setS(true);
		        	}
		        }
		        if(arg0.getKeyCode() == KeyEvent.VK_W){
		        	if(!movingLeft && !movingRight){
		        	player.setW(true);
		        	}
		        }
		        if(arg0.getKeyCode() == KeyEvent.VK_SPACE){
		        	player.setSpace(true);
		        }
	    	}
    	}
    }

    public void keyReleased(KeyEvent arg0) {
    	if(state == 1){
	    	if(arg0.getKeyCode() == KeyEvent.VK_A){
	        	player.setA(false);
	            if(!movingLeft){
	            	player.setIsMoving(false);
	            }
	        }
	        if(arg0.getKeyCode() == KeyEvent.VK_D){
	            player.setD(false);
	            if(!movingRight){
	            	player.setIsMoving(false);
	            }
	        }
	        if(arg0.getKeyCode() == KeyEvent.VK_W){
	            player.setW(false);
	        }
	        if(arg0.getKeyCode() == KeyEvent.VK_S){
	        	player.setS(false);
	        }
	        if(arg0.getKeyCode() == KeyEvent.VK_SPACE){
	            player.setSpace(false);
	        }
    	}
    }

        @Override
    public void keyTyped(KeyEvent arg0) {             
    }
}